/**
 * 
 */
package fr.gfi.agraf.service.impl;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import fr.gfi.agraf.persistence.dao.IComposantDAO;
import fr.gfi.agraf.persistence.dao.INotificationDAO;
import fr.gfi.agraf.persistence.entity.Composant;
import fr.gfi.agraf.persistence.entity.Notification;
import fr.gfi.agraf.service.IDonneesCommunesService;
import fr.gfi.agraf.service.enumeration.CategorieComposantEnum;
import fr.gfi.agraf.service.mapper.ComposantMapper;
import fr.gfi.agraf.service.mapper.NotificationMapper;
import fr.gfi.agraf.vue.bean.ComposantDTO;
import fr.gfi.agraf.vue.bean.DonneesCommunesFront;
import fr.gfi.agraf.vue.bean.NotificationDTO;

/**
 * @author Fw
 * 
 */
@Service("DonneesCommunesService")
@Transactional(propagation = Propagation.REQUIRED)
public class DonneesCommunesService implements IDonneesCommunesService {

	private static final int LIMIT_NOTIFICATION = 25;

	@Autowired
	private IComposantDAO composantDAO;

	@Autowired
	private INotificationDAO notificationDAO;

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * fr.gfi.agraf.service.IDonneesCommunesService#getDonneesCommunes(java.
	 * lang.Long, java.lang.Long)
	 */
	public DonneesCommunesFront getDonneesCommunes(final Long idProfil, final Long idUtilisateur) {
		final DonneesCommunesFront data = new DonneesCommunesFront();

		// Je recherche les composants lié au profil
		final List<Composant> listeComposants = composantDAO.getComposantsParProfil(idProfil);
		getMapComposantByProfil(listeComposants, data);

		// Je recherche les notifications de l'utilisateur
		final List<Notification> listesAllNotifs = notificationDAO.getAllNotificationsByUserLimited(
				idUtilisateur, LIMIT_NOTIFICATION);
		final List<NotificationDTO> listeAllNotifsDTO = new ArrayList<NotificationDTO>();
		for (final Notification notif : listesAllNotifs) {
			listeAllNotifsDTO.add(NotificationMapper.entityToDTO(notif));
		}
		data.setListeNotifications(getListeNotifsNonLues(listesAllNotifs));
		data.setListeNotificationRecentes(listeAllNotifsDTO);

		return data;
	}

	/**
	 * Renvoie la liste sous forme de beans des notifications non lues
	 * 
	 * @param listeEntity
	 * @return une liste de notifications
	 */
	private List<NotificationDTO> getListeNotifsNonLues(final List<Notification> listeEntity) {
		final List<NotificationDTO> output = new ArrayList<NotificationDTO>();

		for (final Notification notification : listeEntity) {
			if (!notification.isVu()) {
				output.add(NotificationMapper.entityToDTO(notification));
			}
		}

		return output;
	}

	/**
	 * Méthode organisant le retour de la map contenant les composants de
	 * l'utilisateur
	 * 
	 * @param listeComposants
	 */
	private void getMapComposantByProfil(final List<Composant> listeComposants,
			final DonneesCommunesFront data) {

		// Je tri la liste car elle provient d'un set
		Collections.sort(listeComposants, new Comparator<Composant>() {
			public int compare(final Composant c0, final Composant c1) {
				return c0.getCategorieComposant().getLibelle()
						.compareTo(c1.getCategorieComposant().getLibelle());
			}
		});

		final Map<CategorieComposantEnum, List<ComposantDTO>> mapOutput = new HashMap<CategorieComposantEnum, List<ComposantDTO>>();
		final List<ComposantDTO> listeOutput = new ArrayList<ComposantDTO>();

		// Et j'alimente la map
		for (final Composant comp : listeComposants) {
			if (comp.getCategorieComposant().getId().equals(CategorieComposantEnum.COMPOSANT_IHM.getId())) {
				listeOutput.add(ComposantMapper.entityToDTO(comp));
				continue;
			}
			List<ComposantDTO> listeCompActuel = mapOutput.get(CategorieComposantEnum
					.getCssByIdCategorie(comp.getCategorieComposant().getId()));
			if (listeCompActuel == null) {
				listeCompActuel = new ArrayList<ComposantDTO>();
			}
			listeCompActuel.add(ComposantMapper.entityToDTO(comp));
			mapOutput.put(CategorieComposantEnum.getCssByIdCategorie(comp.getCategorieComposant().getId()),
					listeCompActuel);
		}

		final Comparator<CategorieComposantEnum> comparator = new Comparator<CategorieComposantEnum>() {
			public int compare(final CategorieComposantEnum cc1, final CategorieComposantEnum cc2) {
				return (int) (cc1.getId() - cc2.getId());
			}
		};
		final Map<CategorieComposantEnum, List<ComposantDTO>> mapTriee = new TreeMap<CategorieComposantEnum, List<ComposantDTO>>(
				comparator);
		mapTriee.putAll(mapOutput);

		data.setMapComposant(mapTriee);
		data.setListeComposantIhm(listeOutput);

	}
}
